package com.bjpowernode.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.bjpowernode.domain.Comments;
import com.bjpowernode.domain.Houses;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.CommentsMapper;
import com.bjpowernode.mapper.UsersMapper;
import com.bjpowernode.model.SpikeConstant;
import com.bjpowernode.service.HousesService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjpowernode.domain.Order;
import com.bjpowernode.mapper.OrderMapper;
import com.bjpowernode.service.OrderService;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Resource
    private HousesService housesService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private CommentsMapper commentsMapper;

    @Resource
    private UsersMapper usersMapper;

    /**
     * 自定义自选阈值时间
     */
    private final Long TIME = 1000L;

    /**
     * 做抢购
     * 1.查询房间表有没有库存
     * 2.扣减房间表库存
     * 3.写订单表
     *
     * @param userId
     * @param houseId
     */
    @Override
    @Transactional
    public void doSpike(Integer userId, String houseId) {
        // 加一个分布式锁 可以使用redis 也可以使用mysql的乐观锁 这里选择使用redis
        // 如果三个线程同时进来，那么只有一个获取到锁 其他两个线程结束了，如果第一个线程没有成功，其他两个就重试不了
        // 所以这里我们手动实现以下自旋
        // 所以这里我们手动实现以下自旋
        long localTimes = 0L;
        // 进行自旋
        while (localTimes < TIME) {
            Boolean absent = stringRedisTemplate.opsForValue().setIfAbsent
                    (SpikeConstant.SPIKE_LOCK + houseId, houseId, 2, TimeUnit.SECONDS);
            if (!ObjectUtils.isEmpty(absent) && absent) {
                // 加锁成功
                // 查询房间表有没有库存
                try {
                    Houses houses = housesService.getById(houseId);
                    int i = houses.getNums() - 1;
                    if (i < 0) {
                        // 说明没有库存了 秒杀失败
                        log.info("这个房子:{} 没有库存了", houseId);
                        return;
                    }
                    // 走到这里表示库存还有,然后设置库存
                    houses.setNums(i);
                    boolean update = housesService.updateById(houses);
                    if (update) {
                        // 写订单表
                        writeOrder(houses, userId);
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    // 别忘记删掉锁了
                    stringRedisTemplate.delete(SpikeConstant.SPIKE_LOCK + houseId);
                }
            }
            // 如果没有获取到锁 就睡200ms 让后再自旋以下相当于给时间续期
            localTimes += 200;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 用户订单查询
     *
     * @param userId
     * @return
     */
    @Override
    public List<Order> getOrdersByUser(String userId) {
        List<Order> orderList = orderMapper.selectList(new LambdaQueryWrapper<Order>()
                .eq(Order::getUser, userId)
                .orderByAsc(Order::getCreateTime)
        );
        if (orderList == null) {
            log.info("用户{}没有订单信息", userId);
        }
        // 处理图片显示
        orderList.forEach(order -> {
            String img = order.getImg();
            if (img.contains(",")) {
                String s = img.split(",")[0];
                order.setImg(s);
            }
        });
        return orderList;
    }

    /**
     * 用户评论接口
     *
     * @param rate
     * @param feelback
     * @param orderId
     * @return
     */
    @Override
    @Transactional
    public Boolean doFeelback(Integer rate, String feelback, Integer orderId) {
        // 查询订单是否存在
        Order order = orderMapper.selectById(orderId);
        if (ObjectUtils.isEmpty(order)) {
            return false;
        }
        // 修改订单评论状态
        order.setCommentState(2);
        int i = orderMapper.updateById(order);
        // 写入评论信息
        if (i > 0){
            // 根据用户id查询信息
            User user = usersMapper.selectById(order.getUser());
            Comments build = Comments.builder()
                    .username(user.getUsername())
                    .comment(feelback)
                    .star(rate)
                    .houseid(order.getHouseId().toString())
                    .build();
            commentsMapper.insert(build);
            return true;

        }
        return false;
    }

    /**
     * 写订单表
     *
     * @param houses
     * @param userId
     */
    private void writeOrder(Houses houses, Integer userId) {
        // 使用雪花算法生成订单号
        Snowflake snowflake = new Snowflake(0, 0);
        String orderNum = snowflake.nextIdStr();
        Order order = Order.builder()
                .createTime(new Date())
                .houseId(houses.getId())
                .img(houses.getImgs())
                .rentType(houses.getRentType())
                .title(houses.getTitle())
                .user(userId)
                .houseType(houses.getHouseType())
                .price(houses.getPrice())
                .commentState(0)
                .orderNum(orderNum)
                .build();
        orderMapper.insert(order);
    }

}
